#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/IR/Constant.h"
#include "llvm/Transforms/Scalar/DCE.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"

#include <set>
#include <iostream>

using namespace llvm;

namespace llvm
{
  FunctionPass *createConstantPropagationPass();
  void initializeConstantPropagationPass(PassRegistry &);
} // namespace llvm

int numInstKill = 0;

namespace
{ //具体结构和给出的样例相同
  struct ConstantPropagation : public FunctionPass
  {
    static char ID;
    ConstantPropagation() : FunctionPass(ID)
    {
      initializeConstantPropagationPass(*PassRegistry::getPassRegistry());
    }

    bool runOnFunction(Function &F) override
    {                      //对函数进行操作
      if (skipFunction(F)) //和Mypass.hpp 情况相同, 判断是否能够进行操作
        return false;

      std::set<Instruction *> WorkList; //Worklist 记录了Function中的指令, 初始化
      for (Instruction &I : instructions(&F))
        WorkList.insert(&I); //将所有Instr 记录到 Worklist 中

      bool MadeChange = false;

      const DataLayout &DL = F.getParent()->getDataLayout();
      TargetLibraryInfo *TLI =  &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);

      std::cout << "the instr deleted by constant prop: {" << std::endl;

      while (!WorkList.empty())
      { //对命令逐行分析
        Instruction *I = *WorkList.begin();
        WorkList.erase(WorkList.begin()); // Get an element from the worklist...

        if (!I->use_empty()) //对有作用的部分的代码进行操作
          if (Constant *Cst = ConstantFoldInstruction(I, DL, TLI))
          { //对I命令进行折叠 ,不能够折叠即返回空

            for (User *U : I->users())
              WorkList.insert(cast<Instruction>(U));

            // Replace all of the uses of a variable with uses of the constant.
            I->replaceAllUsesWith(Cst);

            // Remove the dead instruction.
            WorkList.erase(I);
            if (isInstructionTriviallyDead(I, TLI))
            { //Return true if the result produced by the instruction is not used, and the instruction has no side effects.
              I->eraseFromParent();

              std::cout << " " << I->getOpcodeName() << std::endl;
              ++numInstKill;
            }

            MadeChange = true; //当存在常量传递的消除时, change 标记为 true
          }
      }

      std::cout << "} \n The num of killed instr is: " << numInstKill << std::endl;

      llvm::outs() << "After ConstProp, All Instructions: {\n";
      for (auto I = inst_begin(F), end = inst_end(F); I != end; ++I)
      {
        llvm::outs() << (*I) << "\n";
      }
      llvm::outs() << "}\n";

      return MadeChange;
    }

    void getAnalysisUsage(AnalysisUsage &AU) const override
    {
      AU.setPreservesCFG();
      AU.addRequired<TargetLibraryInfoWrapperPass>();
    }
  };
} // namespace

char ConstantPropagation::ID = 0;
INITIALIZE_PASS_BEGIN(ConstantPropagation, "constprop",
                      "Simple constant propagation", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(ConstantPropagation, "constprop",
                    "Simple constant propagation", false, false)

FunctionPass *llvm::createConstantPropagationPass()
{
  return new ConstantPropagation();
}
